//
//
#ifndef Gmath_h__
#define Gmath_h__

#include "Stdafx.h"

namespace Geometric
{
	class _GEOMETRIC Gmath
	{
	public:
		static inline bool isEqual(double _value1, double _value2)
		{
			return (::fabs(_value1 - _value2) < DBL_EPSILON);
		}

		static inline bool isNotEqual(double _value1, double _value2)
		{
			return (::fabs(_value1 - _value2) >= DBL_EPSILON);
		}

		static inline bool isEqual(double _value1, double _value2, double eps)
		{
			return (::fabs(_value1 - _value2) < eps);
		}

		static inline bool isNotEqual(double _value1, double _value2, double eps)
		{
			return (::fabs(_value1 - _value2) >= eps);
		}

		static inline bool isZero(double _value)
		{
			return (::fabs(_value) < DBL_EPSILON);
		}

		static inline bool isLess(double _value1, double _value2)
		{
			return (_value1 < _value2);
		}

		static inline bool isLessAndEqual(double _value1, double _value2)
		{
			return ((_value1 < _value2) || ::abs(_value2 - _value1) < DBL_EPSILON);
		}

		static inline bool isMore(double _value1, double _value2)
		{
			return (_value1 > _value2);
		}

		static inline bool isMoreAndEqual(double _value1, double _value2)
		{
			return ((_value1 > _value2) || ::abs(_value2 - _value1) < DBL_EPSILON);
		}

		//
		static inline double toAbs(double _value)
		{
			return ::abs(_value);
		}

		static inline double toSqrt(double _value)
		{
			return ::sqrt(_value);
		}

		static inline double toPow(double _base, int _exp)
		{
			return ::pow(_base, _exp);
		}

		static inline double toCeil(double _value)
		{
			return static_cast<double>(ceil(_value));
		}

		static inline double toFloor(double _value)
		{
			return static_cast<double>(floor(_value));
		}

		static inline double toRound(double _value)
		{
			return static_cast<double>(_value < 0 ? (long int)(_value - 0.5) : (long int)(_value + 0.5));
		}

		static inline double toMax(double _value1, double _value2)
		{
			return (_value1 > _value2 ? _value1 : _value2);
		}

		static inline double toMin(double _value1, double _value2)
		{
			return (_value1 < _value2 ? _value1 : _value2);
		}

		static inline long int toTrunc(double _value)
		{
			return static_cast<long int>(_value);
		}

		static inline double toLogE(double _value)
		{
			return ::log(_value);
		}

		static inline int toSign(double _value)
		{
			return (::abs(_value) < DBL_EPSILON) 
				? MATH_SIGN_ZRO : ((_value > 0.0) ? MATH_SIGN_POSITIVE : MATH_SIGN_NEGATIVE);
		}

		static inline bool isSameSign(double _value1, double _value2)
		{
			return (toSign(_value1) == toSign(_value2));
		}
		
		static inline bool isFinite(double _value)
		{
			return static_cast<bool>(::_finite(_value));
		}

		static inline bool isNan(double _value)
		{
			return static_cast<bool>(::_isnan(_value));
		}

		// greatest common divisor
		// if _a or _b is 0, it will lead to a exception
		static inline unsigned int toGreatDivisor(unsigned int _a, unsigned int _b)
		{
			//_a = (_a > 0) ? _a : (-_a);
			//_b = (_b > 0) ? _b : (-_b);			
			if(_a < _b)
			{
				unsigned int tmp = _a;
				_a = _b;
				_b = tmp;
			}

			// _a=_b*q+r
			unsigned int q = _a / _b;
			unsigned int r = _a % _b;
			while(r != 0)
			{
				_a = q;
				_b = r;
				q = _a / _b;
				r = _a % _b;
			}

			return q;
		}

		// least common multiple
		static inline unsigned int toLeastMultiple(unsigned int _a, unsigned int _b)
		{
			//_a = (_a > 0) ? _a : (-_a);
			//_b = (_b > 0) ? _b : (-_b);
			unsigned int common = toGreatDivisor(_a, _b);
			return (_a * _b / common);
		}

		// get specify position number: 987654321
		static inline unsigned int getNumber(unsigned int num, unsigned int index)
		{
			unsigned int m = (unsigned int)pow((float)10, (int)index);
			return (num % (m*10) / m);
		}
	};

}

#endif